<template>
    <div class="file-upload">
        <div class="file-upload-container" @click.prevent="triggerUpload" v-bind="$attrs">
            <slot v-if="fileStatus === 'loading'" name="loading">
                <button class="btn btn-primary" disabled>正在上传...</button>
            </slot>
            <slot v-else-if="fileStatus === 'success'" name="uploaded" :uploadData="uploadData">
                <button class="btn btn-primary">上传成功</button>
            </slot>
            <slot v-else>
                <button class="btn btn-primary">点击上传</button>
            </slot>
        </div>
        <input type="file" class="file-input d-none" ref="fileInput" @change="handleFileChange">
    </div>
</template>

<script setup lang="ts">
import { PropType, ref } from 'vue'
import axios from 'axios'

type UploadStatus = 'ready' | 'success' | 'loading' | 'error'
type CheckFunc = (file: File) => boolean
const props = defineProps({
    action: {
        type: String,
        required: true
    },
    beforeUpload: {
        type: Function as PropType<CheckFunc>
    }
})
const emits = defineEmits(['file-uploaded', 'file-uploaded-error'])
defineOptions({
  inheritAttrs: false
})

const fileInput = ref<null | HTMLInputElement>(null)
const fileStatus = ref<UploadStatus>('ready')
const uploadData = ref()

const triggerUpload = () => {
    if (fileInput.value) {
        fileInput.value.click()
    }
}
const handleFileChange = (e: Event) => {
    const currentTarget = e.target as HTMLInputElement
    if (currentTarget.files && currentTarget.files.length > 0) {
        const files = Array.from(currentTarget.files)
        if (props.beforeUpload) {
            if (!props.beforeUpload(files[0])) {
                return
            }
        }
        fileStatus.value = 'loading'
        const formData = new FormData()
        formData.append('file', files[0])
        axios.post(props.action, formData, {
            headers: {
                'Content-Type': 'multipart/form-data'
            }
        }).then(resp => {
            fileStatus.value = 'success'
            uploadData.value = resp.data
            emits('file-uploaded', resp.data)
        }).catch((err) => {
            fileStatus.value = 'error'
            emits('file-uploaded-error', { err })
        }).finally(() => {
            currentTarget.value = ''
        })
    }
}
</script>